package com.contract.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.contract.common.enums.ContractStateEnum;
import com.contract.common.enums.SexEnum;
import com.contract.common.enums.SignTypeEnum;
import com.contract.common.enums.UserStateEnum;
import com.contract.common.error.BizException;
import com.contract.common.error.JsonReturnCode;
import com.contract.common.util.CommonUtil;
import com.contract.common.util.FileUtil;
import com.contract.mapper.BizContractInfoMapper;
import com.contract.mapper.BizFileMapper;
import com.contract.mapper.BizTemplateMapper;
import com.contract.mapper.SysUserMapper;
import com.contract.pojo.bo.BizContractInfo;
import com.contract.pojo.bo.BizFile;
import com.contract.pojo.bo.BizTemplate;
import com.contract.pojo.bo.SysUser;
import com.contract.pojo.dto.ContractSignDto;
import com.contract.pojo.dto.ContractViewDto;
import com.contract.pojo.dto.CustomDto;
import com.contract.pojo.input.ContractInvalidInput;
import com.contract.pojo.input.ContractQueryInput;
import com.contract.pojo.input.ContractSaveInput;
import com.contract.pojo.input.ContractSignInput;
import com.contract.pojo.output.JsonResult;
import com.contract.pojo.output.PageOutput;
import com.contract.service.common.BaseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 合同service
 *
 * @author liw
 * @version 1.0
 * @date 2022/6/13 11:10
 */
@Slf4j
@Service
public class BizContractInfoService extends BaseService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private BizFileMapper bizFileMapper;

    @Autowired
    private BizContractInfoMapper bizContractInfoMapper;

    @Autowired
    private BizContractInfoService bizContractInfoService;

    @Autowired
    private BizTemplateMapper bizTemplateMapper;

    /**
     * 发放合同
     *
     * @param vo 数据
     * @return 1
     */
    @Transactional(rollbackFor = Exception.class)
    public JsonResult<Long> save(ContractSaveInput vo) {
        BizContractInfo bizContractInfo = dtoConverter.contractVo2Bo(vo);

        BizTemplate bizTemplate = bizTemplateMapper.selectById(bizContractInfo.getTemplateId());
        BizFile templateFile = bizFileMapper.selectById(bizTemplate.getFileId());
        String rootPath = getFileRootPath();
        String templatePath = rootPath + templateFile.getPath();

        String createPath = FileUtil.createFilePath(rootPath) + FileUtil.makeNameByType(FileUtil.DOCX_SUFFIX);
        String docPath = rootPath + createPath;
        convertMap(vo.getMap());
        FileUtil.addWordValue(templatePath, docPath, vo.getMap());

        // doc 转换pdf
        String createPdfPath = FileUtil.createFilePath(rootPath) + FileUtil.makeNameByType(FileUtil.PDF_SUFFIX);
        FileUtil.wordToPdf(docPath, rootPath + createPdfPath);

        // 保存pdf
        BizFile pdfFile = new BizFile();
        pdfFile.setPath(createPdfPath);
        pdfFile.setName(bizContractInfo.getName() + "_" + bizContractInfo.getUserId() + "." + FileUtil.PDF_SUFFIX);
        bizFileMapper.insert(pdfFile);

        // 填充其他信息
        bizContractInfo.setPdfId(pdfFile.getId());
        bizContractInfo.setState(ContractStateEnum.S.getKey());
        bizContractInfo.setInvalidDate(bizContractInfo.getEnd());
        bizContractInfoMapper.insert(bizContractInfo);

        // 更新人员状态
        bizContractInfoService.updateUserState(bizContractInfo.getUserId());

        return JsonResult.success(bizContractInfo.getId());
    }

    /**
     * 查询列表
     *
     * @return data
     */
    public JsonResult<PageOutput<ContractViewDto>> queryList(ContractQueryInput vo) {
        PageOutput.Node<ContractViewDto, ContractViewDto> node = new PageOutput.Node<ContractViewDto, ContractViewDto>()
                .setFun(a -> a);
        if (Boolean.TRUE.equals(vo.getEnable())) {
            Page<ContractViewDto> objectPage = new Page<>(vo.getPageNo(), vo.getPageSize());
            objectPage.setOptimizeCountSql(false);
            node.setPage(bizContractInfoMapper.getList(objectPage, vo));
        } else {
            node.setList(bizContractInfoMapper.getList(vo));
        }
        return JsonResult.success(PageOutput.page(node));
    }

    /**
     * 失效
     *
     * @return data
     */
    @Transactional(rollbackFor = Exception.class)
    public JsonResult<Long> invalid(ContractInvalidInput vo) {
        BizContractInfo bizContractInfo = bizContractInfoMapper.selectById(vo.getId());
        if (bizContractInfo.getState().equals(ContractStateEnum.U.getKey())) {
            return JsonResult.success(vo.getId());
        }
        LocalDate dbDate = bizContractInfo.getInvalidDate();
        LocalDate invalidDate = vo.getInvalidDate();

        if (dbDate.isBefore(invalidDate)) {
            throw new BizException(JsonReturnCode.ERR_PARAM);
        }
        LocalDate now = LocalDate.now();
        LambdaUpdateWrapper<BizContractInfo> uw = new LambdaUpdateWrapper<>();
        uw.eq(BizContractInfo::getId, vo.getId());
        uw.set(BizContractInfo::getInvalidDate, invalidDate);
        uw.set(BizContractInfo::getInvalidReason, vo.getInvalidReason());
        if (invalidDate.isBefore(now) || invalidDate.isBefore(bizContractInfo.getStart())) {
            uw.set(BizContractInfo::getState, ContractStateEnum.U.getKey());
            bizContractInfoMapper.update(null, uw);
            bizContractInfoService.updateUserState(bizContractInfo.getUserId());
        } else {
            bizContractInfoMapper.update(null, uw);
        }
        return JsonResult.success(vo.getId());
    }

    /**
     * 员工签字
     *
     * @return data
     */
    @Transactional(rollbackFor = Exception.class)
    public JsonResult<Long> sign(ContractSignInput vo) {

        BizContractInfo bizContractInfo = bizContractInfoMapper.selectById(vo.getContractId());
        if (!bizContractInfo.getState().equals(ContractStateEnum.S.getKey())) {
            throw new BizException(JsonReturnCode.ERR_CONTRACT_STATE_S);
        }

        String rootPath = getFileRootPath();

        // 获取合同
        BizFile pdfFile = bizFileMapper.selectById(bizContractInfo.getPdfId());

        // 员工签字的图片
        BizFile imgFile = bizFileMapper.selectById(vo.getSignId());

        String createPath = FileUtil.createFilePath(rootPath) + FileUtil.makeFileName(imgFile.getPath());
        FileUtil.rotate(rootPath + imgFile.getPath(), rootPath + createPath);
        imgFile.setPath(createPath);

        // 员工签字
        BizTemplate bizTemplate = bizTemplateMapper.selectById(bizContractInfo.getTemplateId());
        List<ContractSignDto.ImgInfo> sign = JSON.parseArray(bizTemplate.getUserSign(), ContractSignDto.ImgInfo.class);

        // 添加图片和日期
        for (ContractSignDto.ImgInfo imgInfo : sign) {
            if (SignTypeEnum.DATE.getKey().equals(imgInfo.getType())) {
                imgInfo.setValue(LocalDate.now().toString());
            } else if (SignTypeEnum.USER.getKey().equals(imgInfo.getType())) {
                if (CommonUtil.isEmpty(imgInfo.getImgPath())) {
                    imgInfo.setImgPath(rootPath + imgFile.getPath());
                }
            }
        }

        // 添加图片和日期
        for (ContractSignDto.ImgInfo imgInfo : sign) {
            if (SignTypeEnum.DATE.getKey().equals(imgInfo.getType())) {
                imgInfo.setValue(LocalDate.now().toString());
            } else if (SignTypeEnum.USER.getKey().equals(imgInfo.getType())) {
                if (CommonUtil.isEmpty(imgInfo.getImgPath())) {
                    imgInfo.setImgPath(rootPath + imgFile.getPath());
                }
            }
        }


        String pdfName = FileUtil.createFilePath(rootPath) + FileUtil.makeNameByType(FileUtil.PDF_SUFFIX);
        ContractSignDto dto = new ContractSignDto();
        dto.setImgInfoList(sign);
        dto.setFromPath(rootPath + pdfFile.getPath());
        dto.setOutPath(rootPath + pdfName);
        FileUtil.pdfAddImg(dto);

        // 更新合同
        pdfFile.setPath(pdfName);
        bizFileMapper.updateById(pdfFile);

        // 更新合同状态
        LambdaUpdateWrapper<BizContractInfo> contractUw = new LambdaUpdateWrapper<>();
        contractUw.eq(BizContractInfo::getId, vo.getContractId());
        contractUw.set(BizContractInfo::getState, ContractStateEnum.W.getKey());
        contractUw.set(BizContractInfo::getSignId, vo.getSignId());
        contractUw.set(BizContractInfo::getFaceId, vo.getFaceId());
        bizContractInfoMapper.update(null, contractUw);

        // 更新人员状态
        bizContractInfoService.updateUserState(bizContractInfo.getUserId());

        return JsonResult.success(bizContractInfo.getId());
    }

    /**
     * 签章
     *
     * @return data
     */
    @Transactional(rollbackFor = Exception.class)
    public JsonResult<Long> stamp(Long id) {
        BizContractInfo bizContractInfo = bizContractInfoMapper.selectById(id);
        if (!bizContractInfo.getState().equals(ContractStateEnum.W.getKey())) {
            throw new BizException(JsonReturnCode.ERR_CONTRACT_STATE);
        }

        // 合同
        BizFile pdfFile = bizFileMapper.selectById(bizContractInfo.getPdfId());
        String rootPath = getFileRootPath();
        // 公司签章
        BizTemplate bizTemplate = bizTemplateMapper.selectById(bizContractInfo.getTemplateId());
        List<ContractSignDto.ImgInfo> sign = JSON.parseArray(bizTemplate.getCorporationSign(), ContractSignDto.ImgInfo.class);

        ContractSignDto.getValue(sign, rootPath);
        String pdfName = FileUtil.createFilePath(rootPath) + FileUtil.makeNameByType(FileUtil.PDF_SUFFIX);
        ContractSignDto dto = new ContractSignDto();
        dto.setImgInfoList(sign);
        dto.setFromPath(rootPath + pdfFile.getPath());
        dto.setOutPath(rootPath + pdfName);
        FileUtil.pdfAddImg(dto);

        // 更新合同
        pdfFile.setPath(pdfName);
        bizFileMapper.updateById(pdfFile);

        // 更新合同状态
        LambdaUpdateWrapper<BizContractInfo> contractUw = new LambdaUpdateWrapper<>();
        contractUw.eq(BizContractInfo::getId, id);
        if (!bizContractInfo.getStart().isAfter(LocalDate.now())) {
            contractUw.set(BizContractInfo::getState, ContractStateEnum.E.getKey());
        } else {
            contractUw.set(BizContractInfo::getState, ContractStateEnum.P.getKey());
        }
        bizContractInfoMapper.update(null, contractUw);

        // 更新人员状态
        bizContractInfoService.updateUserState(bizContractInfo.getUserId());

        return JsonResult.success(bizContractInfo.getId());
    }

    /**
     * 发放合同
     *
     * @param id 数据
     */
    public void preview(Long id) {

        BizTemplate bizTemplate = bizTemplateMapper.selectById(id);
        BizFile templateFile = bizFileMapper.selectById(bizTemplate.getFileId());
        String rootPath = getFileRootPath();
        String templatePath = rootPath + templateFile.getPath();

        String docPath = rootPath + FileUtil.createFilePath(rootPath) + FileUtil.makeNameByType(FileUtil.DOCX_SUFFIX);
        List<CustomDto> customDtoList = JSON.parseArray(bizTemplate.getCustom(), CustomDto.class);
        Map<String, String> map = customDtoList.stream().collect(Collectors.toMap(CustomDto::getName, CustomDto::getValue));

        // 模拟数据
        map.putAll(FileUtil.USER_INFO_TEST);
        FileUtil.addWordValue(templatePath, docPath, map);

        // doc 转换pdf
        String pdfFromPath = rootPath + FileUtil.createFilePath(rootPath) + FileUtil.makeNameByType(FileUtil.PDF_SUFFIX);
        FileUtil.wordToPdf(docPath, pdfFromPath);

        // 公司签章
        List<ContractSignDto.ImgInfo> sign = JSON.parseArray(bizTemplate.getCorporationSign(), ContractSignDto.ImgInfo.class);
        sign.addAll(JSON.parseArray(bizTemplate.getUserSign(), ContractSignDto.ImgInfo.class));

        ContractSignDto.getValueTest(sign, rootPath);

        String pdfPath = rootPath + FileUtil.createFilePath(rootPath) + FileUtil.makeNameByType(FileUtil.PDF_SUFFIX);
        ContractSignDto dto = new ContractSignDto();
        dto.setImgInfoList(sign);
        dto.setFromPath(pdfFromPath);
        dto.setOutPath(pdfPath);
        FileUtil.pdfAddImg(dto);
        FileUtil.outFile(response(), new File(pdfPath));
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateUserState(Long id) {
        LambdaQueryWrapper<BizContractInfo> qw = new LambdaQueryWrapper<>();
        qw.eq(BizContractInfo::getUserId, id);
        List<BizContractInfo> contractInfoList = bizContractInfoMapper.selectList(qw);
        LambdaUpdateWrapper<SysUser> userUw = new LambdaUpdateWrapper<>();
        userUw.eq(SysUser::getId, id);

        // 无合同，不用操作
        if (CommonUtil.isEmpty(contractInfoList)) {
            userUw.set(SysUser::getState, UserStateEnum.N.getKey());
            sysUserMapper.update(null, userUw);
            return;
        }
        Map<String, List<BizContractInfo>> collect = contractInfoList.stream()
                .collect(Collectors.groupingBy(BizContractInfo::getState));

        // 其他，  修改员工状态为 未在职
        String state = UserStateEnum.U.getKey();
        if (!CommonUtil.isEmpty(collect.get(ContractStateEnum.E.getKey()))) {
            // 生效中， 修改员工状态为 在职
            state = UserStateEnum.O.getKey();
        } else if (!CommonUtil.isEmpty(ContractStateEnum.P.getKey())) {
            // 待生效， 修改员工状态为 待入职
            state = UserStateEnum.W.getKey();
        }
        userUw.set(SysUser::getState, state);
        sysUserMapper.update(null, userUw);
    }

    /**
     * delete
     *
     * @return data
     */
    @Transactional(rollbackFor = Exception.class)
    public JsonResult<Long> delete(Long id) {
        BizContractInfo bizContractInfo = bizContractInfoMapper.selectById(id);
        if (CommonUtil.isEmpty(bizContractInfo)) {
            return JsonResult.success(id);
        }
        bizContractInfoMapper.deleteById(id);
        // 更新人员状态
        bizContractInfoService.updateUserState(bizContractInfo.getUserId());
        return JsonResult.success(id);
    }

    private void convertMap(Map<String, String> map) {
        String key = "sex";
        String sex = map.get(key);
        if (CommonUtil.isEmpty(sex)) {
            return;
        }
        Optional<SexEnum> first = Arrays.stream(SexEnum.values()).filter(item -> item.getKey().equals(sex)).findFirst();
        first.ifPresent(sexEnum -> map.put(key, sexEnum.getValue()));
    }

}
